package org.activiti.engine.impl.bpmn.behavior;

import java.util.ArrayList;
import java.util.List;

import org.activiti.engine.ActivitiException;
import org.activiti.engine.cfg.security.CommandExecutorContext;
import org.activiti.engine.cfg.security.CommandExecutorFactory;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.impl.util.CommandExecutor;
import org.activiti.engine.impl.util.ShellCommandExecutor;
import org.activiti.engine.impl.util.ShellExecutorContext;

public class ShellActivityBehavior extends AbstractBpmnActivityBehavior {

  private static final long serialVersionUID = 1L;

  protected Expression command;
  protected Expression wait;
  protected Expression arg1;
  protected Expression arg2;
  protected Expression arg3;
  protected Expression arg4;
  protected Expression arg5;
  protected Expression outputVariable;
  protected Expression errorCodeVariable;
  protected Expression redirectError;
  protected Expression cleanEnv;
  protected Expression directory;

  String commandStr;
  String arg1Str;
  String arg2Str;
  String arg3Str;
  String arg4Str;
  String arg5Str;
  String waitStr;
  String resultVariableStr;
  String errorCodeVariableStr;
  Boolean waitFlag;
  Boolean redirectErrorFlag;
  Boolean cleanEnvBoolean;
  String directoryStr;

  private void readFields(DelegateExecution execution) {
    commandStr = getStringFromField(command, execution);
    arg1Str = getStringFromField(arg1, execution);
    arg2Str = getStringFromField(arg2, execution);
    arg3Str = getStringFromField(arg3, execution);
    arg4Str = getStringFromField(arg4, execution);
    arg5Str = getStringFromField(arg5, execution);
    waitStr = getStringFromField(wait, execution);
    resultVariableStr = getStringFromField(outputVariable, execution);
    errorCodeVariableStr = getStringFromField(errorCodeVariable, execution);

    String redirectErrorStr = getStringFromField(redirectError, execution);
    String cleanEnvStr = getStringFromField(cleanEnv, execution);

    waitFlag = waitStr == null || waitStr.equals("true");
    redirectErrorFlag = "true".equals(redirectErrorStr);
    cleanEnvBoolean = "true".equals(cleanEnvStr);
    directoryStr = getStringFromField(directory, execution);

  }

  public void execute(DelegateExecution execution) {

        readFields(execution);

        List<String> argList = new ArrayList<String>();
        argList.add(commandStr);

        if (arg1Str != null)
            argList.add(arg1Str);
        if (arg2Str != null)
            argList.add(arg2Str);
        if (arg3Str != null)
            argList.add(arg3Str);
        if (arg4Str != null)
            argList.add(arg4Str);
        if (arg5Str != null)
            argList.add(arg5Str);

        ShellExecutorContext executorContext = new ShellExecutorContext(
                waitFlag,
                cleanEnvBoolean,
                redirectErrorFlag,
                directoryStr,
                resultVariableStr,
                errorCodeVariableStr,
                argList);

        CommandExecutor commandExecutor =  null;

        CommandExecutorFactory shellCommandExecutorFactory = CommandExecutorContext.getShellCommandExecutorFactory();

        if (shellCommandExecutorFactory != null) {
            // if there is a ShellExecutorFactoryProvided
            // then it will be used to create a desired shell command executor.
            commandExecutor = shellCommandExecutorFactory.createExecutor(executorContext);
        } else {
            // default Shell executor (if the shell security is OFF)
            commandExecutor = new ShellCommandExecutor(executorContext);
        }

        try {
            commandExecutor.executeCommand(execution);
        } catch (Exception e) {
            throw new ActivitiException("Could not execute shell command ", e);
        }

        leave(execution);
    }

  protected String getStringFromField(Expression expression, DelegateExecution execution) {
    if (expression != null) {
      Object value = expression.getValue(execution);
      if (value != null) {
        return value.toString();
      }
    }
    return null;
  }

}
